package com.omuao.cloud.stabilization.common.message.core.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.omuao.cloud.stabilization.common.message.annotation.MessageQueue;
import com.omuao.cloud.stabilization.common.message.annotation.MessageQueueDelete;
import com.omuao.cloud.stabilization.common.message.annotation.MessageQueueInsert;
import com.omuao.cloud.stabilization.common.message.annotation.MessageQueueUpdate;
import com.omuao.cloud.stabilization.common.message.core.MessageProducer;
import com.omuao.cloud.stabilization.common.message.core.metadata.MessageQueueData;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * 消息队列方法处理器
 *
 * @author yumi
 */
public class MessageQueueProcessor implements MethodInterceptor {

    public static final String EMPTY_STRING = "";

    public static final String INSERT = "insert";

    public static final String UPDATE = "update";

    public static final String DELETE = "delete";

    public static final String SPLITTER = "_";

    public static Logger logger = LoggerFactory.getLogger(MessageQueueProcessor.class);

    private ApplicationContext applicationContext;

    public MessageQueueProcessor() {
    }

    public MessageQueueProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        MessageProducer messageProducer = applicationContext.getBean(MessageProducer.class);

        /**
         * 目标对象
         */
        Object target = methodInvocation.getThis();

        Class targetClazz = target.getClass();

        MessageQueueData messageQueueData = new MessageQueueData();

        MessageQueue messageQueue = null;

        String topic = null;

        if (targetClazz.isAnnotationPresent(MessageQueue.class)) {

            messageQueue = target.getClass().getAnnotation(MessageQueue.class);

            topic = EMPTY_STRING.equals(messageQueue.value()) ? null : messageQueue.value();

            messageQueueData.setTopic(topic);
        }


        /**
         * 方法
         */
        Method method = methodInvocation.getMethod();

        String tag = null;

        String contentType = "application/json";

        messageQueueData.setContentType(contentType);

        String content = convertData(method.getParameters(), methodInvocation.getArguments(), applicationContext);

        messageQueueData.setBody(content);
        boolean flag = false;

        if (method.isAnnotationPresent(MessageQueueDelete.class)) {
            flag = true;
            MessageQueueDelete messageQueueDelete = method.getAnnotation(MessageQueueDelete.class);
            topic = EMPTY_STRING.equals(messageQueueDelete.topic()) ? topic : messageQueueDelete.topic();
            tag = EMPTY_STRING.equals(messageQueueDelete.value()) ? DELETE : messageQueueDelete.value().concat(SPLITTER).concat(DELETE);
            messageQueueData.setTopic(topic);
            messageQueueData.setTag(tag);
        }

        if (method.isAnnotationPresent(MessageQueueInsert.class)) {
            flag = true;
            MessageQueueInsert messageQueueInsert = method.getAnnotation(MessageQueueInsert.class);
            topic = EMPTY_STRING.equals(messageQueueInsert.topic()) ? topic : messageQueueInsert.topic();
            tag = EMPTY_STRING.equals(messageQueueInsert.value()) ? INSERT : messageQueueInsert.value().concat(SPLITTER).concat(INSERT);
            messageQueueData.setTopic(topic);
            messageQueueData.setTag(tag);
        }

        if (method.isAnnotationPresent(MessageQueueUpdate.class)) {
            flag = true;
            MessageQueueUpdate messageQueueUpdate = method.getAnnotation(MessageQueueUpdate.class);
            topic = EMPTY_STRING.equals(messageQueueUpdate.topic()) ? topic : messageQueueUpdate.topic();
            tag = EMPTY_STRING.equals(messageQueueUpdate.value()) ? UPDATE : messageQueueUpdate.value().concat(SPLITTER).concat(UPDATE);
            messageQueueData.setTopic(topic);
            messageQueueData.setTag(tag);
        }
        Object result = methodInvocation.proceed();
        if (!flag) {
            return result;
        }
        return messageProducer.send(messageQueueData);
    }

    /**
     * 转换数据
     *
     * @param parameters         参数
     * @param arguments          参数值
     * @param applicationContext 应用上下文
     * @return
     * @throws JsonProcessingException
     */
    private String convertData(Parameter[] parameters, Object[] arguments, ApplicationContext applicationContext) throws JsonProcessingException {
        ObjectMapper objectMapper = applicationContext.getBean(ObjectMapper.class);
        String content = null;
        Object parameter = null;
        if (parameters.length == 1) {
            Map data = new HashMap(4);
            data.put(parameters[0].getName(), arguments[0]);
            parameter = data;
        } else {
            Map data = new HashMap(parameters.length * 2);
            for (int i = 0; i < arguments.length; i++) {
                Parameter it = parameters[i];
                data.put(it.getName(), arguments[i]);
            }
            parameter = parameters;
        }

        content = objectMapper.writeValueAsString(parameter);
        return content;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}